device clean#29261
Merged
chrisnojima merged 12 commits intoMay 29, 2026
Merged
Conversation
…heets, rename context
…ature, dedupe icon logic
Documents which style properties can be lifted into Box2 props (purely structural, no visual change) and how to use gap/gapStart/gapEnd to replace per-child margins (slight visual change — must be validated with user before applying). Also relaxes the hard-line no-visual-changes rule to allow validated visual changes with explicit user sign-off.
…ces/
- Extract box2ClassNames() from Box2 desktop branch into shared helper
- Export box2SharedProps from box.tsx
- ClickableBox3Props = Box2Props & {onClick?, onLongPress?, hitSlop?}
- CB3 desktop: box2ClassNames + clickable-box2 CSS class
- CB3 mobile: box2SharedProps + Pressable
- Migrate devices/ CB1/CB2 → CB3, eliminate inner Box2 wrappers
- Simplify mobileAddHeader style (flex/position props move to CB3 props)
- Add plans/clickablebox3.md migration plan with per-directory checklist
- Add/update migrate-clickable-box skill for CB3 migration
Replace fixed-height virtualized List with ScrollView so long TLF names that wrap to multiple lines don't overlap adjacent rows.
4a07f73
into
nojima/HOTPOT-next-670-clean-2
1 of 2 checks passed
chrisnojima
added a commit
that referenced
this pull request
Jun 8, 2026
* HOTPOT next 670 clean
* update deps (#29125)
* internal boundary (#29124)
* move debounce out (#29128)
* WIP
* WIP
* chat refactors (#29123)
* pull non legends list changes from other branch
* other optimizations
* small chat 3 (#29131)
* Engine layer simpler (#29139)
* remove error flow from zus (#29133)
* show profile clean (#29144)
* notif cleanup (#29148)
* slim autoreset (#29147)
* remove more store plumbing (#29149)
* chat move nav to router (#29150)
* team chat split part 1 (#29151)
* more chat cleanup 1 (#29154)
* tb cleanup part 2 (#29155)
* remove registry (#29156)
* remove more defer (#29157)
* fix flip convo id (#29161)
* forward port flip fix
* split up unlock / accounts / config / shell stores (#29162)
* move unlock folders
* split app state into shell store
* move load daemon accounts
* thin settings email more (#29163)
* recover password to flow (#29164)
* recover password to flow
* tb and randompw (#29165)
* tb and randompw
* store split 4 (#29166)
* module cleanup (#29175)
* FS clean (#29176)
* lint hooks (#29177)
* fix perms (#29178)
* more lint 2 (#29180)
* more lint
* lint fixes
* init cleanup subs (#29181)
* chat store shift 1 (#29182)
* update small deps (#29191)
* fix getgregor calls and initial thread load (#29192)
* WIP
* jsi perf test (#29188)
* jsi perf test
* fs slim (#29195)
* update deps (#29196)
* font cleanup (#29198)
* better mobile nav icons (#29199)
* better android nav icons
better ios icons
* test push (#29200)
* dont reload on refocus (#29201)
* update deps (#29202)
* thread crash and push nav dedupe (#29203)
* dont nav if were there
* maymbe makes foreground crashes happen less
* merge master: audio classification, attachment moderation, toast fix
* mm
* initial beta expo 56 (#29204)
* merge master: team member count fixes, info panel keyboard race, UI bugs
* ts split (#29211)
* build: add tsconfig.base.json
* build: add gen-ts-paths.mjs to generate per-platform tsconfig paths
* build: remove unused imports and dead stripExt function from gen-ts-paths.mjs
* build: add generated tsconfig paths files
* build: add tsconfig.desktop.json
* build: add tsconfig.native.json (errors to fix in subsequent tasks)
* build: delete .d.ts stubs replaced by generated tsconfig paths
* fix: restore deleted .d.ts stubs and fix generator to skip .d.ts-covered modules
Task 6 deleted .d.ts files that are still needed for relative imports within
the same package (e.g. `import {Box2} from './box'` in common-adapters files).
The tsconfig paths mappings only intercept `@/*` imports, not relative ones.
Restore all 107 deleted .d.ts stubs. Update gen-ts-paths.mjs to skip emitting
a path entry when a plain .d.ts already exists (avoiding redundant and
conflicting @/foo/index → foo/index.platform entries). Also add bare-directory
path entries (e.g. @/foo → foo/index.platform) for directories that have only
platform-split index files and no index.d.ts.
Result: desktop 0 errors (was 421), native 47 errors (was 450, all pre-existing).
* fix: resolve type errors surfaced by per-platform tsconfig split
* build: tsconfig.json is editor fallback (extends tsconfig.desktop.json)
* build: yarn tsc generates paths and checks desktop + native configs
* build: replace global casts with globals.native.d.ts declarations
Add globals.native.d.ts to properly declare platform-specific globals
(window, location) instead of using `global as {window?: ...}` casts
throughout the codebase.
Also: split make-icons.page to .desktop/.native, fix DataTransfer
augmentation in globals.d.ts for tsgo compatibility, update ESLint to
use per-platform tsconfigs (native-first) so shared files are
type-checked with native types.
* WIP
* build: restore use-resize-observer.d.ts to base version
* replace common-adapters index.d.ts stub with proper platform barrel files
* split tsconfig into per-platform configs, inline types from deleted .d.ts stubs
* WIP
* WIP
* WIP
* WIP
* WIP
* WIP
* WIP
* WIP
* WIP
* WIP
* WIP
* delete orphaned icon.constants-gen.shared-2.tsx
Fragment containing only the IconMeta type with no importers; the type
is already defined in icon.constants-gen.shared.tsx.
* merge platform files (#29212)
* update skill
* update deps and update skill (#29217)
* add inbox unread to accessory view (#29218)
* fix bg css not loading
* fix accessory for inbox
* Use KeyboardChatScrollView in chat thread (#29221)
* bring back translate-with-padding. use KeybaseChatScrollView
* left align unread
* fix files root header offset (#29222)
* Remove zoom toolkit (#29223)
* add implementation plan: replace react-native-zoom-toolkit with local module
* add zoom-toolkit/types.ts
* add zoom-toolkit commons utils
* add zoom-toolkit commons hooks with patches applied
* add zoom-toolkit fitContainer and useImageResolution
* add zoom-toolkit ResumableZoom (trimmed props, patches applied)
* add zoom-toolkit CropZoom (trimmed props, forwardRef inline, dead code removed)
* add zoom-toolkit module index
* update consumer imports to use local zoom-toolkit
* remove react-native-zoom-toolkit npm dep and config references
* fix lint errors in zoom-toolkit: use .set(), if guards, prefer-const, set-state-in-effect
* fix reanimated warning: use .value= in worklets, .set() only on JS thread
* WIP
* remove zoom-toolkit replacement plan doc
* add MIT license attribution for vendored react-native-zoom-toolkit code
* misc android fixes (#29224)
* electron legends list (#29225)
* chat thread: update imports for LegendList migration
* chat thread: delete custom desktop waypoint/scroll system
* chat thread: migrate desktop to LegendList, remove custom virtualization
* chat thread: remove itemLayout from maintainScrollAtEnd to fix ResizeObserver loop
* remove scroll pointer changes
* WIP
* fix scroll hover stop. fix overlay being cut off
* handle unknown duration better
* chat thread: fix search highlight and scroll-to-center for LegendList
LegendList's scrollToIndex uses estimated item positions for unrendered
items, causing it to land far from the target when estimated sizes are
smaller than actual. Fix by adding data-ordinal to each row and using a
retry loop: attempt scrollIntoView on the element directly, falling back
to scrollToIndex to get closer each time until the element is rendered.
Also extract HighlightableRow so it subscribes to the center context
directly, ensuring re-renders propagate through LegendList's recycled
containers. Disable maintainVisibleContentPosition during centering to
prevent it from fighting the scroll.
* feedback
* update plans
* WIP
* WIP
* use yarn 4 (#29229)
* use yarn 4
* Revert "use yarn 4 (#29229)" (#29230)
This reverts commit ab548d577d519143df034613698d9b33194929fc.
* update deps (#29231)
* fix iOS simulator OOM crash when fast-scrolling media-rich chat threads (#29233)
Three fixes for Hermes heap exhaustion in the iOS simulator:
1. FlatList windowSize=3: the default windowSize=21 kept ~262 message
components simultaneously mounted, filling Hermes old-gen with ~340MB of
live JS objects that GC couldn't collect. windowSize=3 limits concurrent
mounted components to ~51. Confirmed: heap now plateaus at ~724MB with GC
collecting successfully instead of crashing at 354MB allocated.
2. SDWebImage cache cap: expo-image's SDWebImage backend keeps decoded bitmaps
in a memory cache. The iOS simulator never sends memory warnings, so the
cache grew unbounded across 400-500 loaded messages. Capped at 100MB via
ExpoImage.configureCache at startup. Confirmed: js_externalBytes stayed
under 1.2MB throughout.
3. CoreMedia thread gating: useVideoPlayer and useAudioPlayer each spawn a
CoreMedia pipeline. Previously called unconditionally for every message in
the list; now gated behind user interaction (or autoPlay for Giphy).
* keyboard send fix (#29235)
* update plan
* fix iOS chat send: list jumps behind keyboard when sending with keyboard open
When the keyboard is open, KeyboardChatScrollView sets contentOffset.y = -(K-I)
via contentInset.top. Three issues caused the list to shift on send:
1. scrollToBottom scrolled to offset=0 instead of -(K-I)
2. maintainVisibleContentPosition autoscrollToTopThreshold=1 fired (-(K-I) <= 1)
and scrolled to y=0, stripping the keyboard offset
3. MPV's per-insertion offset adjustment added message_height to contentOffset,
creating a gap between the newest message and the input area
Fix: compute the correct keyboard-aware offset in scrollToBottom, disable MPV
entirely when the keyboard is visible (new messages appear naturally at the
contentInset boundary), and add a layout-effect safety net that re-scrolls to
bottom when new messages arrive while the keyboard is open.
* replace unsafe useNavigation casts with typed hook (#29237)
Add useTypedNavigation('routeName') in util/typed-navigation.tsx that returns
NativeStackNavigationProp<RootParamList, RouteName>, giving real typing for
setParams/setOptions derived from the global route definitions rather than
local duplicated ParamList types that could drift. Remove 12 local *ParamList
type definitions and all the as-unknown-as / single-as casts they required.
* misc fixes (#29239)
* use global fill abs
* fix lint and use plain rn animated instead of reanimated
* handle recycle
* clean 1 (#29240)
* cleanup
* mass simplify
* remove prettier
* lint
* WIP
* doc fixes (#29241)
* remove fsextra, json5, rimraf (#29242)
* remove fsextra, json5, rimraf
* remove whydid you and scan
* feedback . delete assets to skill
* pr skill
* deps (#29243)
* bump deps (#29243)
* better version skill
* clean lock
* handle prerelease to release
* thread fixes (#29244)
* chat: remove opacity hack from LegendList; rely on its built-in readyToRender
LegendList already hides content (opacity 0) while bootstrapping the initial
scroll position and reveals it once settled. Our outer opacity/didFirstLoad
gate was redundant and introduced a race where onLoad could be missed
(e.g. on first inbox load in Electron), leaving the list permanently hidden.
Drop didFirstLoad state and the style-opacity override entirely; keep onLoad
only for markInitiallyLoadedThreadAsRead.
* dont show cards if not loaded yet
* minheight for top message. handle reations on bottom row not scrolling
* patch legends to not fire resize immediately
* use onStartReached
* remove patch and use onEndReached
* local prettier files
* shared cleanup (#29245)
* shared cleanup
* fix slow device page load (#29246)
* fix: key/fetch_private hangs 60s on stale connections, blocking devices screen
sync_secret.go and per_user_key.go both set RetryCount:5 on their APIArgs
but left InitialTimeout at zero. In doRetry, when InitialTimeout==0 and
RetryCount>0, the per-attempt timeout falls back to cli.cli.Timeout which
is HTTPDefaultTimeout (60s). A stale keep-alive TCP connection in Go's HTTP
pool causes the first attempt to silently hang for the full 60s before the
OS detects the dead connection. Worst case with 5 retries: 5 minutes, which
is why the devices screen appears to never load.
Fix: add InitialTimeout:HTTPRetryInitialTimeout (1s) and the standard
RetryMultiplier to both sites. A stale connection now fails fast, and the
retry gets a fresh connection and succeeds in a few seconds.
* fix typo
* use NewRetryAPIArg
* style helpers. style skill (#29248)
* docs: add border() helper + style analysis skill design spec
* feat: add Kb.Styles.border() helper
* feat: add style analysis script (extract + analyze phases)
* feat: add keybase-style-analysis skill and implementation plan
* refactor: apply Kb.Styles.border() in chat/audio and chat/conversation
* refactor: apply Kb.Styles.border() in devices and provision
* refactor: apply Kb.Styles.border() in chat/emoji-picker and common-adapters
* refactor: apply Kb.Styles.border() in teams
* docs: remove border helper plan and spec docs
* WIP
* feat: add topDivider, roundedBottom, textEllipsis, paddingH/V, marginH/V, size helpers
* feat: add gap detection for topDivider, roundedBottom, textEllipsis, paddingH/V, marginH/V, size
* refactor: apply Kb.Styles.topDivider()
* refactor: apply Kb.Styles.roundedBottom()
* refactor: apply Kb.Styles.textEllipsis
* refactor: apply Kb.Styles.paddingH()
* refactor: apply Kb.Styles.paddingV()
* refactor: apply Kb.Styles.marginH()
* fix: exclude string margin values from marginH gap detector
* refactor: apply Kb.Styles.marginV()
* refactor: apply Kb.Styles.marginV() at remaining wrapper.tsx site
* fix: widen size() to accept percentage strings; exclude undefined from size gap detector
* refactor: apply Kb.Styles.size()
* fix: add new style helpers to Styles mock in confirm.test.tsx
* WIP
* WIP
* WIP
* WIP
* WIP
* fix LegendList deadlock when cached thread data arrives before onLayout (#29249)
* fix LegendList deadlock when cached thread data arrives before onLayout
When initialScrollAtEnd=true and a cached RPC response arrives before
LegendList's ResizeObserver fires, handleInitialScrollDataChange returns
early (queuedInitialLayout=false), leaving didFinishInitialScroll=false
permanently and rendering nothing. Gate data delivery with a rAF so
layout always fires before data arrives.
* fix lint: derive layoutReady from key comparison, avoid synchronous setState in effect
* fix broken mobile assets. remove ts-nocheck which masked this (#29250)
* Merge origin/master into nojima/HOTPOT-next-670-clean-2
* update skill history
* better fix for resize observer, still needed (#29252)
* better fix for resize observer, still needed
* remove resizeobserver
* unused
* done
* delete unused
* fix showDevTools
* update skill
* try and fix selected race
* WIP
* WIP
* WIP
* address copilot pr feedback
- fix wrapperRef type to MeasureRef (matches Box2 expectation), cast to Element inside effect
- fix get-copilot-feedback.sh to match Copilot bot login name
- fix playwright SKILL.md snippet to declare mainPage variable
* add automated e2e tests for Electron and iOS (#29253)
* add e2e test ID constants
* add Playwright E2E infrastructure
* add testID attributes to key app components
* add Playwright smoke tests for all 8 app sections
* add Maestro iOS e2e test flows
* add Playwright critical flow tests
* fix unused browser variable in e2e test files
* gitignore playwright test-results and report dirs
* fix connect.ts to find main app by URL not tab index
* reduce all e2e timeouts to 3s
* fix all 9 smoke tests passing: correct testIDs and .first() for mounted duplicates
- chat/inbox: rename data-testid to match chat-inbox-list constant
- chat/inbox/row: use CHAT_INBOX_ROW constant; ClickableBox2 desktop now renders data-testid
- teams/main: add testID to outer Box2 (Kb.List testID is native-only)
- smoke tests: add .first() for crypto/devices/git where all tabs stay mounted
* move playwright output to shared/tests/results/
* add test:e2e:report script to open HTML report
* use @/ imports in e2e tests instead of relative paths
* use @/ imports for test-ids in component files
* add KB_SMOKE_USER guard, fix chat send test, fix devices row testID
- connect.ts: require KB_SMOKE_USER env var; verify logged-in user matches before running any test
- chat-send-message: find KB_SMOKE_USER's inbox row, assert it's first (most recent), fix message list testID
- list-area/index.tsx: use CHAT_MESSAGE_LIST constant (was hardcoded "message-list" vs "chat-message-list")
- devices/row.tsx: wrap ListItem in Box2 with DEVICES_ROW testID
- devices-view flow: 10s timeout for device rows (async load)
* fix teams-browse: add TEAMS_ROW testID and ClickableBox desktop testID support
* max out playwright report options: retries, trace on failure, json output, test steps
* fix e2e test screenshots and teams stale state
- add KB_E2E_TEST env var: skips menubar widget + devtools windows so
CDP connection only sees the main app window; fixes screenshots
capturing the wrong window
- add start-hot-e2e script (KB_ENABLE_REMOTE_DEBUG=1 KB_E2E_TEST=1)
- refactor tests to use a worker-scoped page fixture (helpers/fixtures.ts)
so Playwright's screenshot machinery targets the correct page
- fix navigateToTeams: double-click tab to pop to root when stale state
leaves the tab inside a team detail page
- simplify connect.ts now that menubar window is suppressed
* add iOS Maestro e2e tests: all 8 tabs smoke + 5 flows with report output
- add testID to native chat inbox Box2 (chat-inbox-list), TextInput (chat-input),
and crypto subnav container (crypto-input) so Maestro can find them on iOS
- add smoke tests for all missing tabs: people, crypto, devices, git (via More tab)
- update smoke-all-tabs.yaml to cover all 8 tabs including More section
- update chat-send-message flow to use KB_SMOKE_USER env var and text-based send
- add test:e2e:ios:all script and junit report output (--format junit) to all ios scripts
* add Maestro workspace config.yaml for subdirectory flow discovery
* fix empty thread after user switch: don't invalidate gen on StrictMode remount
StrictMode double-invokes effects (mount → cleanup → remount). The cleanup
was always incrementing threadLoadGenerationRef, which marked the first
getThreadNonblock RPC as stale. The second RPC then received no content from
the daemon (it deduplicates concurrent requests). Guard the increment behind
a check that the conversation id actually changed, using currentIDRef which
useLayoutEffect keeps up to date.
* fix iOS smoke tests: one screen per test, self-resetting navigation
- replace smoke-all-tabs with 8 individual smoke tests (one screen each)
- setup.yaml runs first to land on People from any starting state
- use Teams pivot (safe from More settings list) to avoid Chat/Files ambiguity
- add E2E mount logs to all 8 tested screens for debugging
- add Maestro workspace config with 60s flow timeout
* add test ids
* remove debug E2E mount logging from screen components
* use exampleuser in connect.ts comment instead of real username
* switch iOS e2e report to HTML-DETAILED with debug output and screenshots on failure
* fix ios report output filename to include .html extension
* add screenshots and custom HTML report to iOS smoke tests
- takeScreenshot in each smoke test now saves to tests/results/ios-debug/
- generate-ios-report.mts builds a self-contained HTML report with embedded screenshots
- yarn test:e2e:ios:smoke clears stale debug output, runs maestro, then generates report
- add optional backButton at start of smoke-devices and smoke-teams to handle case where previous test's back-navigation hadn't completed
* add visual diff comparison to iOS smoke test report
Each run saves previous screenshots to ios-prev/ before running,
then the HTML report shows a before/after drag slider for each screen.
Pixel diff % (using pngjs) is shown as a badge — blue (<1%), yellow (<5%), red (≥5%).
yarn test:e2e:ios:save-baseline pins the current run as the comparison baseline.
* add electron report, fix slider lag, stable baseline management
Slider: pointer events + rAF + CSS custom props (no more getBoundingClientRect on every move)
iOS baseline: test scripts no longer auto-update ios-prev/; only
yarn test:e2e:ios:save-baseline touches it so comparisons stay stable
Electron report: generate-electron-report.mts reads Playwright results.json,
shows same grid/slider format; yarn test:e2e:electron:save-baseline pins baseline,
yarn test:e2e:electron:report opens the report
Enable screenshot:on in Playwright config so each test captures a screenshot
* fix slider: prevent browser image drag hijacking pointer events
preventDefault on mousedown + dragstart handler stops the browser from
entering native drag mode (which changed the cursor to a globe and
killed mousemove events after a few pixels). Use window-level
mousemove/mouseup so dragging outside the element continues to track.
* add expand-to-overlay for image comparison in both reports
Hovering any card shows a ⤢ button. Clicking it opens a full-screen overlay:
- Compare cards: large before/after drag slider (85vh, same UX as inline)
- Solo screenshots: full-size image view
Click backdrop or press Escape to close.
* address PR feedback: fix testID cross-platform, e2e lint and report
- Forward testID to native branches in ClickableBox and ScrollView
- Remove wrapping Box2 in left-nav; testID now on ScrollView directly
- Align native chat inbox row and message list testIDs with constants
- Fix Maestro escape-to-tabs: replace unsupported tapOn timeout with runFlow/when pattern
- Fix electron report to read screenshot from path when body is absent
- Remove redundant fixture screenshot; use playwright screenshot: on
- Fix lint: no-empty-pattern in fixtures, CommandStatus type, unnecessary nullish coalescing
- Exclude tests/results from ESLint to prevent formatter crash
* address PR feedback: testIDs, HTML escaping, lint fixes
- Forward testID in SwipeConvActions using constant instead of hardcoded "inboxRow"
- Update Maestro flows and perf tooling for renamed testIDs (inboxRow→chat-inbox-row, messageList→chat-message-list, inbox-list→chat-inbox-list, message-list→chat-message-list)
- Prevent React DOM warning: extract testID from passThroughProps before spreading onto <div> in ClickableBox
- Add HTML escaping for error messages and labels in iOS/Electron report generators
- Fix no-empty-pattern lint: replace {} destructuring with _fixtures param in fixture
- Rename T import to TestIDs in input.tsx to avoid confusion with types alias
- Add comment on pngjs transitive dependency usage
* fix jest: exclude playwright e2e tests; fix thread load invalidation on unmount
- Exclude tests/e2e/electron from Jest's testPathIgnorePatterns so Playwright tests don't run under Jest
- Add mountedRef to track true unmount vs StrictMode cleanup in ConversationThreadLoadStatusProvider; isThreadLoadCurrent() now returns false after genuine unmount while still avoiding the StrictMode double-increment issue
* fix playwright fixture: restore {} destructuring required by playwright's static analysis
* add comment explaining why {} destructuring is required in playwright fixture
* remove duplicate testID from inner Box2; outer SwipeConvActions wrapper already has it
* speed up perf tests: replace Maestro swipes with idb for settle-free rapid scrolling
* restore NUM_RUNS default to 3 for median collection
* WIP
* teams in common on profile page (#29247)
* teams in common on profile page
* tsc
* automation2 (#29255)
* iOS e2e report: show all screenshots and add baseline comparison
- Fix screenshot naming in crypto-subtabs.yaml (drop flow- prefix so report generator matches them)
- Show one card per screenshot instead of only the last; filter out setup flow
- Add baseline comparison slider (matching Electron report) and yarn test:e2e:ios:save-baseline script
* wip: branch state
* plan: never wrap in Box2 just for testID
* crypto e2e: move testID to existing elements, no new wrapper boxes
- Add testID prop to KeyboardAvoidingView2 (mobile) and DragAndDrop (desktop)
- Remove the extra Box2 wrappers added solely to carry testID
* fix css, decouple from testid
* restore original Box2 wrappers inside DragAndDrop IO components
* bring back non log rn-start2 alternative
* WIP
* WIP
* WIP
* update deps. gh 3. electron now wants safe storeage, so disabling that (#29258)
* update deps. gh 3. electorn now wants safe storeage, so disabling that
* clarify use-mock-keychain comment: covers all keychain-backed Chromium features
* update deps: expo 56.0.7, @legendapp/list 3.0.0 (stable); fix semver script
* sectionlist clean (#29259)
* sectionlist: make renderItem optional, bake in renderSectionHeader delegation
* sectionlist: remove Omit<SectionType, renderItem> hacks
* sectionlist: remove renderSectionHeader delegation boilerplate from info-panel callers
* sectionlist: fix test optional chaining after renderItem became optional
* ignore docs
* common-adapters: remove unused/narrow-use components (#29260)
- Delete TeamWithPopup (unused everywhere)
- Delete timeline-marker.meta.tsx (single color constant, inlined)
- Move TimelineMarker to system-git-push/ (only caller)
- Move PlatformIcon to profile/ (only callers are in profile/)
- Remove BottomSheetModal/Backdrop/ScrollView from index (only used
internally in popup/, not via Kb.*)
- Remove ProfileCard from index (wired internally, never imported
externally)
- Box2Animated removed; callers use createAnimatedComponent(Kb.Box2)
or Animated.createAnimatedComponent(Kb.Box2) locally
- Remove dead ReAnimated={} export from index
- Remove duplicate ConnectedNameWithIcon alias (same as NameWithIcon)
- box.tsx: import Reanimated from ./reanimated instead of directly
from react-native-reanimated
* device clean (#29261)
* devices: clean up structure and organization
* skills: move simplify-ui-section to repo skill
* devices: simplify ui section — extract icon type helper, merge stylesheets, rename context
* devices: fold rpc.tsx into common.tsx, flatten getDeviceIconType signature, dedupe icon logic
* devices: fix getIcon fallback to be type-aware, use object-literal pattern
* skill: add Box2 props and gap guidance to simplify-ui-section
Documents which style properties can be lifted into Box2 props (purely
structural, no visual change) and how to use gap/gapStart/gapEnd to
replace per-child margins (slight visual change — must be validated with
user before applying). Also relaxes the hard-line no-visual-changes rule
to allow validated visual changes with explicit user sign-off.
* common-adapters: add ClickableBox3 (Box2 + click props), migrate devices/
- Extract box2ClassNames() from Box2 desktop branch into shared helper
- Export box2SharedProps from box.tsx
- ClickableBox3Props = Box2Props & {onClick?, onLongPress?, hitSlop?}
- CB3 desktop: box2ClassNames + clickable-box2 CSS class
- CB3 mobile: box2SharedProps + Pressable
- Migrate devices/ CB1/CB2 → CB3, eliminate inner Box2 wrappers
- Simplify mobileAddHeader style (flex/position props move to CB3 props)
- Add plans/clickablebox3.md migration plan with per-directory checklist
- Add/update migrate-clickable-box skill for CB3 migration
* plans: mark CB3 implementation and devices/ pilot as done
* common-adapters: move ClickableBox3 impl into box.tsx
* WIP
* devices: fix TLF list overflow in revoke screen
Replace fixed-height virtualized List with ScrollView so long TLF names that wrap to multiple lines don't overlap adjacent rows.
* devices: simplify UI — remove redundant wrappers, move HeaderTitle to common
* clickablebox 3 - 1 (#29262)
* update ui skill
* simplify-ui-section skill: add iteration loop after implementation
Adds Step 6 directing the model to re-read and re-analyze files after
each implementation pass, stopping only when a full pass yields no
meaningful findings. Also updates the flowchart to show the loop.
* provision: lazy-require expo-camera to fix Electron crash
expo-camera uses native code that crashes on Electron at import time.
Move the require inside the mobile-only component body so it never
evaluates on desktop.
* migrate CB/CB2 → CB3: git, incoming-share, signup, provision, people, settings
* fix settings-item CB3: add fullWidth to prevent alignSelf:center shrinking list rows
* fix ClickableBox3: forward missing props to both desktop and mobile
Desktop: onMouseDown/Leave/Move/Up, onContextMenu, title, tooltip/data-tooltip.
Mobile: onLayout, collapsable, pointerEvents.
* WIP
* cb3 2 (#29263)
* migrate CB/CB2 → CB3: profile
* migrate CB/CB2 → CB3: tracker, menubar, app, router-v2
* clean up iconContainer: remove redundant clickable/flexBoxColumn, fold in icon size
* update skill
* add onMouseEnter to Box2Props and forward it in ClickableBox3 desktop
* fix lint: suppress consistent-type-imports for expo-camera require cast
* skill
* WIP
* deps (#29265)
* metro: block non-source folders from file watcher
* deps: bump expo and related packages
* cb3 4 (#29266)
* clickablebox 3 - teams (#29265)
* clickablebox 3 - team-building (#29265)
* clickablebox 3 - fs (#29265)
* only pick up the folders from shared
* fix profile dropdown button full-width regression on mobile (#29265)
* fix fs sort button content-sizing regression on desktop (#29265)
* fix fs path-item header and destination-picker full-width regression on mobile (#29265)
* update migrate-clickable-box skill with fullWidth gotchas (#29265)
* cb3 5 (#29267)
* migrate shared/chat/ ClickableBox/CB2 → CB3
* migrate shared/common-adapters/ ClickableBox/CB2 → CB3
* complete ClickableBox3 migration: remove legacy CB1/CB2 exports
* WIP
* fixes
* Fix info panel tabs: natural width, centered text, divider spans full tab width
* WIP
* fix prove-your dialog items to be full width
Without fullWidth={true}, ClickableBox3 gets alignSelf:center applied,
centering each provider row instead of spanning the modal width.
* fix CardListItem body text centering: add fullWidth to body Box2
Nested Box2 direction="vertical" without fullWidth gets box2_centered
(align-self:center) applied, horizontally centering it within its
column flex parent. Fixed across all CardListItem callers and in
list-item.tsx's body wrapper.
* remove ChoiceList/RichButton, replace usages with ListItem Card
* remove ClickableBox/ClickableBox2 and migration plan — all usages migrated to ClickableBox3
* mass clean (#29268)
* simplify-ui: git/ — remove redundant wrappers, dead styles/comments, normalize patterns
* simplify-ui: devices/ — deduplicate icon logic, extract constants, replace style props
* simplify-ui: wallets/ — rename Container, extract shared styles, remove redundant props
* simplify-ui: tracker/ — fix hover-opacity typo, dedup utilities, rename Container, replace flexShrink props
* simplify-ui: settings/ — remove redundant wrappers, move styles to props, clean dead code
* simplify-ui: crypto/ — inline IIFEs, merge imports, clean up style props and names
* simplify-ui: teams/ — merge styles, fix functions-as-values, extract string constants, remove wrappers
* simplify-ui: signup/ — extract shared input width, fix prop shorthands, remove dead code
* simplify-ui: people/ — remove identity maps, dead code, inline wrappers, move style props
* simplify-ui: profile/ — remove dead code, dedup styles, replace Kb shims, noShrink props
* address PR feedback: safe nav in async callback, fix avatar overlay positioning, restore .tsx extension
* simplify-ui: full codebase pass — rename Containers, remove dead code, move style props
Ran simplify-ui-section skill across all UI directories via parallel subagents:
chat/, common-adapters/, fs/, login/, provision/, team-building/, unlock-folders/,
menubar/, pinentry/, incoming-share/, deeplinks/, router-v2/, and revisits of
profile/, people/, signup/, crypto/, teams/, settings/, tracker/, wallets/,
devices/, git/.
* fix back button hover area: remove inline-block and size(14) from iconContainer
The 14×14px fixed size caused the hover highlight to appear only in the
upper-left corner while the icon extended beyond it. The container now
sizes naturally around the icon with padding defining the hit area.
* fix Checkbox centering: add alignSelf=flex-start to ClickableBox3
* WIP
* fix iOS e2e: restore testID on mobile crypto nav rows
The RichButton→ListItem migration dropped testID; wrap ListItem in Box2 to carry it.
* more e2e test (#29269)
* Add e2e screen tests for Electron desktop
- Test coverage for: chat, crypto, devices, files, git, people/profile, settings (all subpages), teams (browse + inner tabs)
- Add testIDs to nav tabs (tab-bar.desktop.tsx), settings subpages, teams body/tabs, files TLF rows, profile page
- Fixture reloads page at worker start to clear stale state
- navigateToTeams uses force:true to bypass WebkitAppRegion:drag blocking the Teams nav tab when a team detail is open
- teams-inner tests use text-based selectors to avoid dependency on testIDs that require app rebuild
* Fix skipped e2e desktop tests for files navigation and git rows
- Add GIT_REPO_ROW testID to git row component (was defined but never applied)
- Remove test.fixme guards from files folder navigation tests (KBFS UI works without mount)
- Fix files folder navigation assertions to use filter textbox instead of files-browser testID (nav stack keeps root screen mounted/hidden, causing strict mode violations)
- Remove conditional skip from git repo row test
* Add iOS Maestro flows for files navigation and git, add e2e skill
- Add files-folders.yaml: tap each TLF type row, verify back button appears (confirms subfolder navigation), navigate back to root
- Add git.yaml: navigate via More → Git, verify git-repo-list renders, conditional screenshot if rows present
- Update branch scripts to run files-folders + git flows on both platforms
- Add keybase-e2e-tests skill capturing two-harness structure, testID rules, iOS nav patterns, and Playwright gotchas
- Update plans/flow-test.md to reference skill and track progress on buckets 12 and 13
* Bucket 2: crypto output tests (Electron all 4, iOS encrypt+sign)
- Add CRYPTO_OUTPUT testID to CryptoOutput success-state Box2 in output.tsx
- crypto-outputs.test.ts: type text in each tab, auto-run triggers, verify output renders
- Decrypt: encrypts first then feeds ciphertext to decrypt input
- Verify: signs first then feeds signed text to verify input
- Scope CRYPTO_OUTPUT query to tab container (TabRouter mounts all tabs simultaneously)
- Use .last() for textbox selection (encrypt tab has two: recipients + main input)
- crypto-outputs.yaml (iOS): encrypt and sign outputs; decrypt/verify need clipboard support
- Update branch scripts and plan
* Bucket 3: chat conversation view iOS flow
- chat-conversation.yaml: open first inbox row, verify message list renders, navigate back
- Desktop tests already existed and pass
- Update branch scripts and plan
* Buckets 5+6: settings subpages iOS flow (About, Advanced, Display, Notifications, Feedback)
- settings-subpages.yaml: navigate More → each settings page, verify testID renders, back
- Desktop tests already exist and pass (9 tests: Advanced, About, Backup, Chat, Display,
Feedback, Files, Notifications, Screen Protector)
- Password modal skipped (needs Account settings navigation + no testID)
- Update branch scripts and plan; note Bucket 6 partially covered by existing iOS flows
* Buckets 9 + 11: team detail tabs and people/profile iOS flows
- teams-inner.yaml: open first team, navigate Members/Settings/Bots/Channels tabs
- people-profile.yaml: People feed renders; profile via conditional username tap in feed
- Desktop tests already existed and pass (6 tests)
- Update branch scripts and plan
* Buckets 6+8: device detail test + settings subpages Bucket 6 iOS
- Add DEVICE_PAGE testID to device-page.tsx + test-ids.ts
- device-detail.test.ts: click first device row, verify device-page renders
- device-detail.yaml: More → Devices → tap row → verify device-page
- Extend settings-subpages.yaml with Chat, Files, Backup (Bucket 6 iOS items)
- Update branch scripts and plan
* Bucket 10: team member page test
- Add TEAMS_MEMBER_PAGE testID to member/index.new.tsx + test-ids.ts
- team-member.test.ts: click smoke user's username in member list, verify page renders
- team-member.yaml: iOS equivalent using KB_SMOKE_USER env var
- Update branch scripts and plan
* Fix crypto-outputs and settings-subpages iOS e2e tests
crypto-outputs: tapOn text "Encrypt" was hitting the nav header title
instead of the button. Added testID support to ButtonProps/ButtonNative
and CRYPTO_RUN_BUTTON testID to InputActionsBar. Encrypt/sign output is a
modal sheet with Cancel (not backButton), so navigation updated to
Cancel + backButton. Added scrollUntilVisible for Crypto since the More
screen retains scroll position across test runs.
settings-subpages: "About" and "Notifications" require scrolling (in a
separate section below the Settings list). Added scrollUntilVisible for
both. Reordered items top-to-bottom to minimize needed scrolls. Fixed
settings-files testID missing from the mobile render path.
escape-to-tabs: added swipe DOWN at end to reset scroll position at the
start of each flow, preventing stale More screen scroll state from
breaking subsequent flows.
* Plumb testIDs through ListItem and StillCommon instead of wrapper boxes
Rather than wrapping components in an extra Box2 just to attach a testID,
add testID support to ListItem (passed to ClickableBox3) and StillCommon
(passed to ListItem). Remove the wrapper boxes in tlf-type.tsx and
teams/team/index.tsx. Move TEAMS_BODY testID to the SectionList.
* Use KeyboardStickyView for crypto input action bars on iOS (#29270)
* Use KeyboardStickyView for crypto input action bars on iOS
Replaces KeyboardAvoidingView2 with KeyboardStickyView (react-native-keyboard-controller) for the bottom action bar on all four crypto input pages (encrypt, decrypt, sign, verify). The sticky view uses Reanimated to track keyboard height frame-by-frame on the UI thread, eliminating the layout-recalculation lag that caused the bar to trail the keyboard animation.
* try codegraph
* Address Copilot PR feedback on e2e desktop tests
- Skip own-profile test when KB_SMOKE_USER is unset
- Use NAV_TAB_CHAT/NAV_TAB_FILES testID constants instead of text= selectors
- Use NAV_TAB_CHAT constant in fixtures.ts waitFor (was hard-coded string)
- Update flow-test.md and PERF-TESTING.md script names: electron→desktop
* Address second round of Copilot PR feedback
- Wire testID as data-testid in ButtonDesktop
- git repo row test: wait for rows with timeout instead of instant count check
- teams members tab: assert on TEAMS_MEMBER_LIST testID instead of brittle text
* Rename ClickableBox3 → ClickableBox across codebase (#29273)
* Simplify UI across shared/ — Box2 props, style utilities, dead code (#29274)
Batch simplification pass across ~150 files in chat, common-adapters,
teams, fs, settings, profile, login, team-building, provision, crypto,
signup, unlock-folders, people, devices, tracker, wallets, git, app,
menubar, pinentry, and incoming-share.
Key changes:
- Box2 props: migrate alignItems/centerChildren/fullWidth/noShrink/flex/
padding/relative/overflow out of style objects
- Style utilities: Styles.size(), paddingH/V(), marginH/V(), padding(),
bottomDivider(), border(), fillAbsolute(), rounded(), textEllipsis
- Remove redundant wrapper Box2 layers and dead style entries
- Collapse double-nested Box2s where inner props can merge to outer
Net: -325 lines
* update skill
* Simplify UI across shared/ — Box2 props, style utilities, dead code (#29275) (#29275)
143 files changed: move layout properties from stylesheets to Box2 props
(fullWidth, padding, alignItems, noShrink, relative, flex, etc.), replace
inline style objects with Kb.Styles utilities (size, paddingH/V, marginH/V,
bottomDivider, textEllipsis), and remove dead style keys and unused imports.
Also fix pre-existing `electron` → `isElectron` bug in add-to-channels.tsx.
* storybook and better reports (#29276)
* Add Storybook for desktop platform with devices/ stories
- .storybook/main.ts: webpack5 config reusing desktop alias/babel/define patterns
- .storybook/mocks/electron.ts: KB2 stub so platform.tsx loads without Electron preload
- .storybook/preview.ts: injects globalThis._fromPreload, base decorator
- .storybook/preview-head.html: font-face + CSS reset via staticDirs fonts
- staticDirs: fonts/electron + images served at correct URL paths
- tsconfig.desktop.json: include .storybook/ files
- devices/device-icon.stories.tsx: 7 stories
- devices/row.stories.tsx: 6 stories (incl. BadgedDeviceIDsContext)
- devices/device-page.stories.tsx: 6 stories
- plans/storybook.md: todo list of remaining shared/ folders
Run with: cd shared && yarn storybook
* Add storybook screenshots to desktop e2e report and baseline
- generate-electron-report: parse storybook-desktop/ PNGs, render as
separate section with slider diff vs storybook-prev/ baseline
- generate-ios-report: add .section-hdr CSS for full-width grid divider
- save-baseline now also saves storybook screenshots to storybook-prev/
- package.json: add storybook:screenshot script
* storybook
* Add slideshow and lazy loading to e2e HTML reports
- `loading="lazy"` on all report images
- Slideshow button in header: opens full-screen modal, cycles images at 0.75s with CSS fade-in
- Controls bar: prev/next/pause buttons + counter (e.g. 5/233)
- Keyboard: ←/→ navigate, Space toggles play/pause, Esc closes
* Fix dark mode in storybook screenshots and e2e tests
Use page.emulateMedia({colorScheme}) to set prefers-color-scheme via CDP
instead of document.documentElement.style.colorScheme. This activates
@media (prefers-color-scheme: dark) CSS rules that the real app depends on.
- screenshot-storybook.mts: emulateMedia before each light/dark capture
- fixtures.ts: emulateMedia replaces setNativeTheme for dark e2e project
- playwright.config.ts: add electron-flows-dark project
* WIP
* Replace chrisnojima with testuser in all stories/tests
* Address Copilot PR feedback
- Use Playwright bundled Chromium when CHROME_PATH is unset (fixes CI)
- Skip dark mode dispatch when preference is already correct
- Remove unnecessary `as any` cast in announcement story
* Address more Copilot PR feedback
- Fix webpack resolve.extensions order so .desktop.tsx/.desktop.ts take precedence over .tsx/.ts
- Wrap fixture setup() in try/finally so emulateMedia cleanup always runs
- Bind static file server to 127.0.0.1 and sandbox request paths to buildDir
* Fix screenshot summary to show done/total instead of total
* Address more Copilot PR feedback
- Treat flaky-but-passing Playwright tests as passed
- Escape label/name in HTML alt attributes
- Remove unnecessary ?? fallback on non-nullable projectName
* Address more Copilot PR feedback
- Clear storybook output dir before each run to remove stale screenshots
- Include skipped tests as passing in electron report
- Fix storybook label path separator replacement to be global
* Merge master: 6.6.3 changelog + bump golang.org/x/image to v0.41.0
Applies f60f2ff97e and c067f2a368 from master.
* update merge-master skill history
* Speed up devices list by using local cache for lastUsedTime (#29277)
* Speed up devices list by using local cache for lastUsedTime
DeviceHistoryList was calling SyncSecretsForce on every load, triggering
a blocking network request to key/fetch_private that took 0.8–4s.
Now reads lastUsedTime from local LevelDB cache (sub-millisecond), with
a background goroutine that force-syncs after the response is returned.
When the background sync completes, a keyfamilyChanged notification fires
so the devices screen auto-refreshes with fresh data — no user action needed.
* Address PR feedback: fix misleading comment and retry on sync failure
- Fix comment in device_history.go: cache fallback is "out-of-date" not "expired"
- Reset lastDeviceSync on background sync failure so next UI refresh retries immediately instead of waiting out the TTL
* Address PR feedback: consistent unknown lastUsed UX, targeted notify
- device-page.tsx: show "Last used unknown" in timeline when lastUsed is
missing (non-revoked device), matching list row behavior
- device.go: call NotifyRouter.HandleKeyfamilyChanged directly instead of
KeyfamilyChanged to avoid unnecessary BustLocalUserCache + HandleUserChanged
on background sync completion
* Address PR feedback: uid-filter keyfamilyChanged, fix UID source, clarify comment
- Filter keyfamilyChanged listener to current user's uid to avoid
unnecessary DeviceHistoryList RPCs when other users' caches bust
- Use mctx.ActiveDevice().UID() in backgroundSyncDevices instead of
h.G().Env.GetUID() for correct/robust uid source
- Fix misleading "empty or out-of-date" comment in getLastUsedTimes;
forced sync only triggers on empty cache (zero devices)
* Address PR feedback: use defer for mutex unlock
* Address PR feedback: remove unnecessary closure around mutex
* Add NotifyDeviceHistory notification; replace keyfamilyChanged with deviceHistoryChanged for device list refresh
* Wire up deviceHistoryChanged notification on TS side
* Address PR feedback: merge redundant shouldSync conditionals
* Fix stale comment referencing keyfamilyChanged
* Revert keyfamily: true; subscribe to devicehistory instead
* Remove keyfamilyChanged RPC wiring added by this PR; not needed
* Regenerate protocol files via make build; add deviceHistoryChanged to enabled-calls.json
* rerun gen
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* format
* regen
* Fix TestDeviceHistoryBasic: force sync when active device missing from cache
During signup, SyncSecrets populates the LevelDB cache with only the
desktop device before the paper key is provisioned. SyncSecretsFromCache
then finds a valid cache (desktop has non-zero LastUsedTime), skips the
network sync, and the paper device ends up absent from lastUsedTimes,
leaving LastUsedTime = 0.
Fix: after building lastUsedTimes from cache, scan non-revoked devices.
If any is missing, call SyncSecretsForce once to get fresh data covering
all provisioned devices.
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* style fixes (#29280)
* fix(crypto): left-align signed-by sender strip
* fix(tabs): center tab label within its full-width container
* unify reporting
* Fix signup crash: click event laundered into username route param (#29281)
ReloginContainer wired useRequestAutoInvite()'s raw fn directly as
onSignup, so the click event became the `username` arg, flowed through
navigateAppend as a route param, and crashed signup's username.trim().
Make the hook param required (username: string) so a bare assignment to
a () => void handler prop is now a compile error, preventing the event
from being laundered into a string-typed slot. No-username callers pass
'' explicitly.
* fix(list): render header/footer even when items is empty (#29282)
Teams tab was blank for new users — no create/join buttons, no lone
wolf message. Kb.List returned null when items.length === 0, silently
discarding ListHeaderComponent and ListFooterComponent.
* fix(chat): auto-select first conversation on desktop/tablet inbox (#29284)
* more clean (#29285)
* refactor(chat): add makeMessageWrapper factory to cut wrapper boilerplate
Collapse 14 near-identical message-row wrapper.tsx files (~19 lines each)
into ~7-line makeMessageWrapper calls. Factory captures the
useWrapperMessageWithMessage hook, type guard, and WrapperMessage wrapping;
each render callback keeps its own lazy require('./container') so the child
stays code-split. system-sbs-resolve and placeholder stay hand-written
(extra hooks). Net -162 lines.
* refactor(chat): merge selectable row containers into their views
selectable-small-team-container and selectable-big-team-channel-container
were redux-era passthrough wrappers (call hook, build props, render view).
Fold the useInboxRowSmall/Big hook, getRowStyles, participant sort, and
name-split logic into selectable-small-team and selectable-big-team-channel
directly; delete the container files; point inbox-search at the views.
Also drop the dead subColor branch from getRowStyles (never consumed).
* refactor(chat): fold system message containers into their wrappers
For 9 system message types with no external importers, inline the
container.tsx component directly into wrapper.tsx (one file per type) and
drop the require('./container') + typeof-cast indirection now that
makeMessageWrapper handles the boilerplate. Trades the per-type lazy chunk
for fewer files. Left separate: system-joined, system-users-added-to-conv,
system-old-profile-reset-notice, system-sbs-resolve (cross-imported), and
system-change-avatar (index-based).
* tooling(chat): add analyze-styles script for style-helper gap detection
AST-based scanner (extract + analyze) that finds inline style objects which
could use Kb.Styles helpers (border, padding, size, textEllipsis, dividers)
and surfaces new-helper candidate clusters. Backs the keybase-style-analysis
skill. Run from shared/: node scripts/analyze-styles.mts extract|analyze.
* refactor(chat): move layout props from style objects to Box2 props
users suggestor: alignItems:'center' style + justifyContent='center' prop ->
centerChildren on the special-mention icon box.
selectable-small-team: flexShrink:0 -> noShrink prop on the badge box.
These are the only two movable-prop sites in chat; an AST scan confirms the
rest of the chat tree already expresses layout via Box2 props.
* skill(merge-passthrough-containers): detect+fold redux-era pass-through containers
AST detector finds default-exported components that only call hooks, build a
props object, and render ONE self-closing sibling view (no children of their
own). Reports view-reuse and cross-feature signals so shared/adapter views are
flagged SKIP, leaving genuine 1:1 container/view pairs to merge. SKILL.md
documents the verify-then-merge process. Run from shared/:
node ../.claude/skills/merge-passthrough-containers/scripts/find-passthrough-containers.mts <dir>
* refactor: fold pass-through containers into their views
mention, tlf-info-line, relogin containers each just called hooks,
built props, and rendered one sibling view. Move that logic into the
view, delete the container, repoint importers.
* fix: address PR feedback on wrapper child check and report script escaping
- makeMessageWrapper: distinguish empty ReactNode (0, '') from null/undefined/false
- analyze-styles buildHtml: escape < in embedded JSON to prevent </script> breakout
* chore: remove stale wrapper comment
* fix(e2e-report): make 'Pixel diff only' filter actually filter
Card data-has-diff was set whenever a baseline comparison ran, even
when zero pixels changed, so every card matched and the toggle did
nothing. Tag the attribute only when changed > 0 while keeping the
checkbox visible whenever baselines exist.
* fix: address PR feedback on relogin effect, sort, and skill doc path
- relogin: update prevErrorRef inside effect so empty->non-empty error
transition detection works after the first render
- selectable-small-team: clone before sort, short-circuit empty filter,
use transitive comparator
- merge-passthrough-containers script: correct run path to ../.claude
* fix(desktop): dim modal backdrop over inbox header
React Navigation gives each screen header zIndex:1, so the inbox
search + new-chat header painted above the modal backdrop. Give the
backdrop z-index:2 so it dims the header too.
* fix(desktop): allow frame-src for localhost PDF rendering
Chromium renders <embed> PDFs via an internal viewer frame governed by
frame-src, so frame-src 'none' blocked KBFS-served PDFs with
ERR_BLOCKED_BY_CSP. Restore frame-src http://127.0.0.1:*.
* chore(deps): bump dependencies (#29287)
- electron 42.3.0 -> 42.3.3 (+ checksums)
- react-native-reanimated 4.4.0 -> 4.4.1 (drop obsolete patch)
- react-native-keyboard-controller 1.21.8 -> 1.21.9
- @callstack/liquid-glass 0.7.1 -> 0.8.0
- date-fns 4.3.0 -> 4.4.0
- storybook 10.4.1 -> 10.4.2
- eslint 10.4.0 -> 10.4.1, typescript-eslint 8.60.0 -> 8.60.1
- @typescript/native-preview dev bump
* fix(mobile): restrict screen rotation to full-screen attachments (#29288)
* fix(mobile): restrict screen rotation to full-screen attachments
Lock all mobile screens to portrait by default; only the chat and files
full-screen attachment previews opt back into rotation via orientation: 'all'.
* fix(mobile): allow full-screen attachment rotation on Android too
Drop the iOS-only gate so chat and files full-screen previews get
orientation: 'all' on both platforms; presentation: 'transparentModal'
stays iOS-only.
* ios fixes (#29289)
* fix(ios): bundle device Debug via Expo CLI to avoid packed source-map crash
RN community bundle CLI lacks Expo metro-config's packed-source-map
unwrap patch, so a device Debug build (bundles with --sourcemap-output)
threw 'Unexpected module with full source map found' on the require.js
polyfill. Point CLI_PATH/BUNDLE_COMMAND at @expo/cli export:embed.
Use a plain path rather than 'node --print require.resolve' so it works
when Xcode's stripped PATH leaves NODE_BINARY empty at source time.
* fix(chat): mark live messages read in open thread on phones
On phones, chatConversation lives in the root stack as a sibling of the
tab navigator (above the tab bar), so it sits at routes[1+] alongside
real modals. getVisiblePath treated everything at routes[1+] as a modal,
so getVisibleScreen(includeModals=false) — used by getSelectedConversation
— dropped chatConversation and returned noConversationIDKey. That made
isUserActivelyLookingAtThisThread always false on phones, so incoming
messages received while viewing a thread were added with markAsRead:false
and showed as unread after navigating back. Initial mark-read worked
because it uses the loadMoreMessages path, not isUserActivelyLooking.
Distinguish real modals from genuinely-visible pushed root screens via a
config-derived set instead of a hand-maintained allow-list. A serialized
NavigationState route doesn't carry its presentation, so modal-ness can't
be detected structurally; modalRoutes is the single source of truth.
router-v2 registers it at startup via setModalRouteNames.
* fix(chat): seed inbox row participants in activity order
Small-team inbox rows seeded their participant list from the canonical
TLF name (alphabetical), then got overwritten by the participant fetch
in activity order, causing a visible reshuffle on startup. Seed from the
cached WriterNames (activity order) instead, intersected with the
TLF-name writers to exclude bots, dropping self except in self-convs, so
the seed matches what the frontend settles on and the row stays put.
* fix(chat): collapse iOS thread header actions into overflow menu
Replace the two separate native header buttons (search + info) with a
single ellipsis overflow menu so the thread header reclaims room under
the new styling.
* fix(chat): address PR feedback on inbox row seeding
Extract TLF writers from the writer portion only (before #readers and
extension suffix) when seeding ad-hoc inbox row names; reset modal route
names after each router-visible test to avoid worker-level leakage.
* fix(chat): require modal route registration; filter resolved PR comments
Throw from isRootModalRoute if setModalRouteNames was never called instead
of silently treating all root-stack modals as non-modals. Point the test
nav state index at the topmost route. Switch the Copilot feedback script to
GraphQL review threads so resolved/outdated comments are filtered out.
* fix(chat): enable iOS 26 tab bar minimize on all tabs
tabBarMinimizeBehavior was force-disabled by a top-level 'none' override
and was never set on liquid glass. Enable it for iOS.
List-based tab roots (inbox, teams, files) wrap their scroll view in a
styled Box2; RN view-flattening hoists the scroll view to a sibling so
iOS 26 can't find the tab's content scroll view. Add collapsable={false}
on those wrappers. The fs Errs container also always rendered an empty
Box2 as the first child, dead-ending scroll-view detection — return null
when there are no errors.
Minimize still requires enough scrollable content to trigger (short lists
like People/More/fs-recents won't minimize), which is expected behavior.
* android fix (#29290)
* fix(android): guard iOS-only expo-image configureCache
configureCache is iOS-only native in expo-image 56; unguarded module-load
call threw on Android, aborting registerComponent and crashing startup.
* fix(android): apply bottom safe-area inset to pushed stack screens
Android targets SDK 35+ which enforces edge-to-edge, so pushed stack
screens drew content under the system nav bar. Mirror TabScreenWrapper
and wrap StackScreenWrapper in RNScreensSafeAreaView with a bottom edge
on Android.
* fix(mobile): hide bottom tab bar when drilling into Files folders
The bottom tab bar only hides for screens that live in the app root stack
(above the tabs). Other tabs push distinct routes there; Files was the
exception because tapping a folder re-pushed fsRoot inside the fsTab stack,
keeping the bar visible.
Add fsBrowse (same screen as fsRoot, but not a tab root) so on phones it
lands in the root stack and hides the tab bar on push, matching every other
tab. Route within-Files folder navigation (folder taps, parent nav, conflict
/reset banners, destination-picker) through fsBrowse; leave outside-Files
entries (navToPath, deeplinks, linking) on fsRoot so they still land in the
Files tab. public-reminder dismiss now targets the current route so its
replace collapses to setParams instead of a cross-stack replace; daemon
treats fsBrowse as an fs screen.
* chore(android): bump deps, fix gradle warnings, fix android:debug launch
- bump work-runtime 2.11.1->2.11.2, firebase-messaging 25.0.1->25.0.2,
msgpack-core 0.9.10->0.9.12
- fix Gradle 9->10 space-assignment deprecations in our build.gradle files
(ndkVersion/namespace/multiDexEnabled/signingConfig/maven url)
- android:debug now builds+installs+launches MainActivity directly via a
script instead of expo run:android, avoiding the broken
keybase://expo-development-client deep link (no expo-dev-client bundled)
* chore(deps): bump dependencies (#29291)
- legendapp/list, react-navigation alphas, expo patches, electron-packager,
keyboard-controller, typescript native-preview, @types/react
- fix useRoute/NavigationContainer typing for nav alpha bump
- update-dependencies skill: always bump @types/react + sync resolutions
* small fixes (#29292)
* fix(crypto): center copy toast text and fix Android off-center
- Add textAlign center to crypto copy-to-clipboard toast text so wrapped
lines center inside the circular toast (iOS + Android)
- Remove KeyboardAvoidingView2 from native Toast: behavior='height' on
Android collapsed the container, anchoring the fillAbsolute overlay to
the trigger button instead of the screen. A pointerEvents='none' toast
has no input, so keyboard avoidance was unnecessary.
* fix done button in crypto
* feat(modals): Done-right for info/viewer modals
Add doneModalOptions helper + HeaderRightButton: info-only/viewer/live-apply
modals now dismiss with a right-side Done (iOS convention) instead of left
Cancel. Move crypto output modals' Done from left to right. Flip chatInfoPanel,
chatSearchBots, chatLocationPreview, chatUnfurlMapPopup, settingsContactsJoined,
profileImport, profileProveWebsiteChoice. Narrow HeaderLeftButton mode to
back|cancel.
* fix(settings): left-align proxy type radio buttons on mobile
RadioButton renders a ClickableBox without fullWidth, defaulting to
alignSelf: center, so each proxy type radio centered itself. Pin
alignSelf to flex-start.
* fix(common-adapters): left-align RadioButton on mobile
ClickableBox defaults to alignSelf: center without fullWidth, centering
each radio. Pin container alignSelf to flex-start so radios left-align
everywhere (proxy settings, link previews, etc). Drop the per-instance
override added to proxy settings.
* fix(common-adapters): tighten doneModalOptions return type
GetOptionsRet is a union including undefined; the function always returns
an object, so spread call sites (chat/profile routes) had a possibly-undefined
spread. Narrow to NonNullable<GetOptionsRet>.
---------
Co-authored-by: chrisnojima <cnojima@keyba.se>
Co-authored-by: zoom-ua <65734190+zoom-ua@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.